package org.juiceshop.musi;

import java.util.HashMap;
import java.util.Map;


/**
 * Abstract base class for notes, chords, and phrases.
 * @param <ThisType> Actual subclass.
 */
public abstract class MusicObject implements Cloneable {

	private Map<String,Object> _properties;
	private MusicContainer _parent;
	
	/**
	 * Returns property value with given name.
	 * If this object doesn't contain the named property, parent objects are recursively searched.
	 * If no parent object has a property with this name, <code>null</code> is returned.
	 * @param name Name of property looked for.
	 * @return Property value, if found on this or a parent object, otherwise <code.
	 */
	public Object get(final String name) {
		if (_properties!=null && _properties.containsKey(name)) {
			return _properties.get(name);
		}
		if (_parent!=null) {
			return _parent.get(name);
		}
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public <T> T get(String name, T defaultValue) {
		Object value = get(name);
		if (value==null) return defaultValue;
		return (T)value;
	}
	
	public void set(String name, Object value) {
		if (_properties==null) {
			_properties = new HashMap<String, Object>();
		}
		_properties.put(name, value);
	}
	
	protected void setParent(MusicContainer container) {
		if (_parent!=null) {
			throw new IllegalStateException("Parent already set to "+_parent);
		}
		_parent = container;
	}
	
	@Override
	public MusicObject clone() {
		try {
			return (MusicObject)super.clone();
		} catch (CloneNotSupportedException e) {
			throw new Error(e);
		}
	}
	
	/**
	 * Determine musical value.
	 * @return Length of object in ticks.
	 */
	public abstract double getValue();
	
	/**
	 * Determine number of notes.
	 * @return Number of notes in this element.
	 */
	public abstract int size();
	
        		
//	public ThisType copyArgs(Object...args) {
//		if (args.length%2!=0) {
//			throw new IllegalArgumentException("Need equal number of args but got "+args.length);
//		}
//		HashMap<String,Object> map = new HashMap<String, Object>();
//		for (int i=0; i<args.length; i+=2) {
//			map.put((String)args[i], args[i+1]);
//		}
//		return copy(map);
//	}

	
	public abstract MusicObject transpose(int steps);
	
	
//	@SuppressWarnings("unchecked")
//	protected Class<ThisType> thisClass() {
//		return (Class<ThisType>)this.getClass();
//	}
	
}
